#ifndef _MANAGER_H_
#define _MANAGER_H_

#include <unordered_map>
#include <string>
#include <any>
#include <optional>
#include <SECore/ResourcePayload.h>

namespace SEngine
{
    class Manager
    {
    public:
        static Manager & GetInstance();
        virtual ~Manager() = default;

        template<typename T>
        typename ResRef<T> Register(const std::string & name, std::shared_ptr<ResourcePayload<T>> && t) {
            auto & pool = m_pool[typeid(T).hash_code()];
            if (pool.find(name) != pool.end()) {
                pool.erase(name);
            }
            pool.emplace(name, std::move(t));
            return std::dynamic_pointer_cast<ResourcePayload<T>>(pool.at(name))->GetRef();
        }

        template<typename T>
        typename ResRef<T> Register(const std::string & name, const std::string & path, std::unique_ptr<T> && t) {
            auto payload = std::make_shared<ResourcePayload<T>>(name, path, std::move(t));
            return Register(name, std::move(payload));
        }

        template<typename T>
        std::optional<typename ResRef<T>> Get(const std::string name) {
            if (m_pool.find(typeid(T).hash_code()) == m_pool.end()) {
                return std::nullopt;
            }
            auto & pool = m_pool[typeid(T).hash_code()];
            if (pool.find(name) == pool.end()) {
                return std::nullopt;
            }
            return std::dynamic_pointer_cast<ResourcePayload<T>>(pool.at(name))->GetRef();
        }

        template<typename T>
        void Remove(const std::string & name) {
            if (m_pool.find(typeid(T).hash_code()) != m_pool.end()) {
                m_pool.at(typeid(T).hash_code()).erase(name);
            }
        } 

        template<typename T>
        void Foreach(std::function<void(ResRef<T> &)> && fn) {
            if (m_pool.find(typeid(T).hash_code()) != m_pool.end()) {
                for (auto & [_, res] : m_pool.at(typeid(T).hash_code())) {
                    fn(std::dynamic_pointer_cast<ResourcePayload<T>>(res)->GetRef());
                }
            }
        }

        void Clear() { m_pool.clear(); }
    
    private:
        Manager() = default;

    private:
        std::unordered_map<size_t, std::unordered_map<std::string, std::shared_ptr<Resource>>> m_pool;
    };
} // namespace SEngine


#endif